/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package server.managerServer;

/**
 *
 * @author radu
 */
import protocol.*;
import java.io.BufferedReader;
import protocol.Message;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import server.PollList;
import protocol.Executor;
import server.Poll;

/**
 * Thread serving one "admin" TCP connection Is spawned by
 * ManagerServerAcceptor.
 *
 */
public class ServerWorker extends ThreadWorker {

    public final static int UPDATE_INTERVAL = 2;
    private String adminEmail;
    private boolean connectionClossed = false;
    private Socket socket;
    private DataOutputStream output = null;
    private BufferedReader input = null;
    private List<Message> messageQueue = new LinkedList();
    private ThreadReader reader;
    private ThreadWriter writer;
    private PollList polls;
    private List<Poll> watchedPolls;

    public ServerWorker(Socket socket, PollList _polls) throws IOException {
        this.watchedPolls = new ArrayList<>();
        this.socket = socket;
        this.polls = _polls;

        this.input = new BufferedReader(new InputStreamReader(socket.getInputStream(), Charset.forName("ASCII")));
        try {
            this.output = new DataOutputStream(socket.getOutputStream());
        } catch (IOException ex) {
            this.input.close();
            throw ex;
        }

    }

    public PollList getPolls() {
        return polls;
    }

    @Override
    public void run() {
        reader = new ThreadReader(input, this);
        writer = new ThreadWriter(output, this);
        reader.start();
        writer.start();


        long timeout = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(UPDATE_INTERVAL);
        Message message = null;
        while (!connectionClossed) {

            // Wait for data to become available
            long toWait = timeout - System.currentTimeMillis();
            synchronized (messageQueue) {

                while (!connectionClossed && messageQueue.isEmpty() && toWait > 0) {
                    try {
                        messageQueue.wait(toWait);
                    } catch (InterruptedException e) {
                    }
                    toWait = timeout - System.currentTimeMillis();
                }

                if (!messageQueue.isEmpty()) {
                    message = messageQueue.remove(0);
                }
            }

            if (message != null) {
                //System.out.println("LOLOLO");
                Executor exec = message.getServerExecutor();
                exec.doWork(this);
            }
            message = null;

            if (toWait <= 0) {
                timeout += TimeUnit.SECONDS.toMillis(UPDATE_INTERVAL);

                for (Poll p : watchedPolls) {
                    if (p.isEnabled()) {
                        sendMessage(new MessageUpdate(p.getStats(), p.getId()));
                    }
                }
            }

            // Return to sender
            //dataEvent.server.send(dataEvent.socket, dataEvent.data);
        }
        System.out.println("Clossing");
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("Admin connection finished");
        super.finalize();
        try {
            input.close();
        } catch (Exception e) {
        }
        try {
            output.close();
        } catch (Exception e) {
        }

        if (!socket.isClosed()) {
            socket.close();
        }

    }

    @Override
    public void receiveMessage(Message message) {
        synchronized (messageQueue) {
            messageQueue.add(message);
            messageQueue.notify();
        }
    }

    @Override
    public synchronized void closeConnection() {
        connectionClossed = true;
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    public String getAdminEmail() {
        return this.adminEmail;
    }

    public void setAdminEmail(String adminEmail) {
        this.adminEmail = adminEmail;
    }

    @Override
    public void sendMessage(Message msg) {
        writer.queueToWrite(msg);
    }

    public boolean startPoll(long pollId) {
        Poll poll = polls.getPoll(pollId);
        if (poll == null) {
            return false;
        }
        if (!poll.start()) {
            return false;
        }
        watchedPolls.add(poll);
        return true;
    }

    public boolean stopPoll(long pollId) {
        Poll poll = polls.getPoll(pollId);
        if (poll == null) {
            return false;
        }
        if (!poll.stop()) {
            return false;
        }
        watchedPolls.remove(poll);
        return true;
    }

    public long createPoll(String[] options, String adminEmail) {
        Poll poll = polls.createPoll(options, adminEmail);

        return poll.getId();

    }

    public boolean pausePoll(long pollId) {
        Poll poll = polls.getPoll(pollId);
        if (poll == null) {
            return false;
        }
        if (!poll.pause()) {
            return false;
        }
        return true;
    }

    public boolean resumePoll(long pollId) {
        Poll poll = polls.getPoll(pollId);
        if (poll == null) {
            return false;
        }
        if (!poll.resume()) {
            return false;
        }
        return true;
    }
}
